package org.spider.download.httpclient;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.spider.model.DownloadProxy;
import org.spider.model.DownloadRequest;
import org.spider.model.HttpHeader;
import org.spider.utils.UrlUtils;

/**
 * @author code4crafter@gmail.com
 *         Date: 17/3/18
 *         Time: 11:28
 *
 * @since 0.7.0
 */
public class HttpUriRequestConverter {

    public HttpClientRequestContext convert(DownloadRequest downloadRequest) {
        HttpClientRequestContext httpClientRequestContext = new HttpClientRequestContext();
        httpClientRequestContext.setHttpUriRequest(convertHttpUriRequest(downloadRequest));
        httpClientRequestContext.setHttpClientContext(convertHttpClientContext(downloadRequest.getDownloadProxy()));
        return httpClientRequestContext;
    }

    private HttpClientContext convertHttpClientContext(DownloadProxy downloadProxy) {
        HttpClientContext httpContext = new HttpClientContext();
        if (downloadProxy != null && downloadProxy.getUsername() != null) {
            AuthState authState = new AuthState();
            authState.update(new BasicScheme(), new UsernamePasswordCredentials(downloadProxy.getUsername(), downloadProxy.getPassword()));
            httpContext.setAttribute(HttpClientContext.PROXY_AUTH_STATE, authState);
        }
        return httpContext;
    }

    private HttpUriRequest convertHttpUriRequest(DownloadRequest downloadRequest) {
        RequestBuilder requestBuilder = selectRequestMethod(downloadRequest).setUri(UrlUtils.fixIllegalCharacterInUrl(downloadRequest.getUrl()));
        if (downloadRequest.getHttpHeaderList() != null) {
            for (HttpHeader httpHeader : downloadRequest.getHttpHeaderList()) {
                requestBuilder.addHeader(httpHeader.getHeaderName(), httpHeader.getHeaderValue());
            }
        }
        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
        requestConfigBuilder.setConnectionRequestTimeout(downloadRequest.getConnectionRequestTimeout())
                .setSocketTimeout(downloadRequest.getSocketTimeout())
                .setConnectTimeout(downloadRequest.getConnectTimeout())
                .setCookieSpec(CookieSpecs.STANDARD)
                .setRedirectsEnabled(downloadRequest.isRedirectsEnabled())
                // 相对的循环重定向是否拒绝
                .setRelativeRedirectsAllowed(downloadRequest.isRelativeRedirectsAllowed())
                // 循环 重定向是否被允许;
                .setCircularRedirectsAllowed(downloadRequest.isCircularRedirectsAllowed());

        if (downloadRequest.getDownloadProxy() != null) {
            requestConfigBuilder.setProxy(new HttpHost(downloadRequest.getDownloadProxy().getIp(), downloadRequest.getDownloadProxy().getPort()));
        }
        requestBuilder.setConfig(requestConfigBuilder.build());
        return requestBuilder.build();
    }

    private RequestBuilder selectRequestMethod(DownloadRequest downloadRequest) {
        switch (downloadRequest.getHttpMethodEnum()){
            case GET:
                return RequestBuilder.get();
            case POST:
                return addFormParams(RequestBuilder.post(), downloadRequest);
            case HEAD:
                return RequestBuilder.head();
            case PUT:
                return addFormParams(RequestBuilder.put(), downloadRequest);
            case DELETE:
                return RequestBuilder.delete();
            case TRACE:
                return RequestBuilder.trace();
            default:
                throw new IllegalArgumentException("Illegal HTTP Method " + downloadRequest);
        }
    }

    private RequestBuilder addFormParams(RequestBuilder requestBuilder, DownloadRequest downloadRequest) {
        if (downloadRequest.getRequestBody() != null) {
            ByteArrayEntity entity = new ByteArrayEntity(downloadRequest.getRequestBody().getBody());
            entity.setContentType(downloadRequest.getRequestBody().getContentType());
            requestBuilder.setEntity(entity);
        }
        return requestBuilder;
    }
}
